package com.ctvit.sjk.knowledge.document.controller;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.ctvit.sjk.knowledge.core.controller.KnowledgeController;
import com.ctvit.sjk.knowledge.core.page.TableRecordInfo;
import com.ctvit.sjk.knowledge.dataset.pojo.domain.TabDataset;
import com.ctvit.sjk.knowledge.dataset.service.ITabDatasetService;
import com.ctvit.sjk.knowledge.document.pojo.domain.TabDocument;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentBatchCreateDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentBatchDeleteDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentBatchHitHandlingDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentBatchRefreshDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentCancelTaskDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentQueryDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentRefreshDTO;
import com.ctvit.sjk.knowledge.document.pojo.dto.DocumentUpdateDTO;
import com.ctvit.sjk.knowledge.document.pojo.vo.DocumentGetVO;
import com.ctvit.sjk.knowledge.document.pojo.vo.DocumentSplitVO;
import com.ctvit.sjk.knowledge.document.service.ITabDocumentService;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 文档Controller
 *
 * @author heyingcheng
 * @date 2025/3/22
 */
@Slf4j
@RestController
@RequestMapping("knowledge/dataset")
public class TabDocumentController extends KnowledgeController {

    private final ITabDocumentService tabDocumentService;

    private final ITabDatasetService tabDatasetService;

    public TabDocumentController(ITabDocumentService tabDocumentService, ITabDatasetService tabDatasetService) {
        this.tabDocumentService = tabDocumentService;
        this.tabDatasetService = tabDatasetService;
    }

    /**
     * 获取知识库文档列表
     */
    @GetMapping("{datasetId}/document/{pageNum}/{pageSize}")
    public TableRecordInfo list(@PathVariable String datasetId,
                                @PathVariable int pageNum,
                                @PathVariable int pageSize,
                                @RequestParam(value = "name", required = false) String name,
                                @RequestParam(value = "status", required = false) String status,
                                @RequestParam(value = "task_type", required = false) Integer taskType,
                                @RequestParam(value = "hit_handling_method", required = false) String hitHandlingMethod,
                                @RequestParam(value = "is_active", required = false) Boolean activeFlag,
                                @RequestParam(value = "order_by", required = false) String orderBy) {
        DocumentQueryDTO dto = new DocumentQueryDTO(name, status, taskType, hitHandlingMethod, activeFlag, orderBy);

        startPage(pageNum, pageSize);
        return getRecordTable(tabDocumentService.list(datasetId, dto), pageNum, pageSize);
    }

    /**
     * 批量创建知识库文档
     */
    @Log(title = "文档", businessType = BusinessType.INSERT)
    @PostMapping("{datasetId}/document/_bach")
    public AjaxResult batchCreate(@PathVariable String datasetId, @RequestBody List<DocumentBatchCreateDTO> dtoList) {
        TabDataset entity = tabDatasetService.getById(datasetId);
        return success(tabDocumentService.batchCreate(entity, dtoList, CREATE_ID));
    }

    /**
     * 获取知识库文档列表
     */
    @Log(title = "文档", businessType = BusinessType.DELETE)
    @DeleteMapping("{datasetId}/document/_bach")
    public AjaxResult batchDelete(@PathVariable String datasetId, @RequestBody DocumentBatchDeleteDTO dto) {
        return toAjax(tabDocumentService.batchDelete(datasetId, dto, CREATE_ID));
    }

    /**
     * 更新知识库文档
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/{documentId}")
    public AjaxResult update(@PathVariable String datasetId, @PathVariable String documentId, @RequestBody DocumentUpdateDTO dto) {
        LambdaUpdateWrapper<TabDocument> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(Objects.nonNull(dto.getMeta()), TabDocument::getDocumentMetadata, JSON.toJSONString(dto.getMeta()));
        wrapper.set(StringUtils.isNotBlank(dto.getHitHandlingMethod()), TabDocument::getHitHandlingMethod, dto.getHitHandlingMethod());
        wrapper.set(Objects.nonNull(dto.getDirectlyReturnSimilarity()), TabDocument::getDirectlyReturnSimilarity, dto.getDirectlyReturnSimilarity());
        wrapper.set(Objects.nonNull(dto.getIsActive()), TabDocument::getActiveFlag, dto.getIsActive());
        wrapper.set(TabDocument::getUpdateId, CREATE_ID);
        wrapper.set(TabDocument::getUpdateTime, LocalDateTime.now());
        wrapper.eq(TabDocument::getDocumentId, documentId);
        wrapper.eq(TabDocument::getDatasetId, datasetId);

        if (tabDocumentService.update(wrapper)) {
            TabDocument entity = tabDocumentService.getById(documentId);
            return success(new DocumentGetVO(entity));
        }

        return AjaxResult.error();
    }

    /**
     * 迁移知识库文档
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/migrate/{targetId}")
    public AjaxResult migrate(@PathVariable String datasetId, @PathVariable String targetId, @RequestBody List<String> documentIdList) {
        LambdaUpdateWrapper<TabDocument> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(TabDocument::getDatasetId, targetId);
        wrapper.set(TabDocument::getUpdateId, CREATE_ID);
        wrapper.set(TabDocument::getUpdateTime, LocalDateTime.now());
        wrapper.in(TabDocument::getDocumentId, documentIdList);
        wrapper.eq(TabDocument::getDatasetId, datasetId);

        return success(tabDocumentService.update(wrapper));
    }

    /**
     * 批量知识库文档命中处理方式
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/batch_hit_handling")
    public AjaxResult batchHitHandling(@PathVariable String datasetId, @RequestBody DocumentBatchHitHandlingDTO dto) {
        LambdaUpdateWrapper<TabDocument> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(TabDocument::getHitHandlingMethod, dto.getHitHandlingMethod());
        wrapper.set(TabDocument::getDirectlyReturnSimilarity, dto.getDirectlyReturnSimilarity());
        wrapper.set(TabDocument::getUpdateId, CREATE_ID);
        wrapper.set(TabDocument::getUpdateTime, LocalDateTime.now());
        wrapper.in(TabDocument::getDocumentId, dto.getIdList());
        wrapper.eq(TabDocument::getDatasetId, datasetId);

        return success(tabDocumentService.update(wrapper));
    }

    /**
     * 批量知识库文档向量化
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/{documentId}/refresh")
    public AjaxResult batchRefresh(@PathVariable String datasetId, @PathVariable String documentId, @RequestBody DocumentRefreshDTO dto) {
        return success(tabDocumentService.refresh(datasetId, documentId, dto, CREATE_ID));
    }

    /**
     * 批量知识库文档向量化
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/batch_refresh")
    public AjaxResult batchRefresh(@PathVariable String datasetId, @RequestBody DocumentBatchRefreshDTO dto) {
        return success(tabDocumentService.batchRefresh(datasetId, dto, CREATE_ID));
    }

    /**
     * 批量知识库文档向量化
     */
    @Log(title = "文档", businessType = BusinessType.UPDATE)
    @PutMapping("{datasetId}/document/{documentId}/cancel_task")
    public AjaxResult cancelTask(@PathVariable String datasetId, @PathVariable String documentId, @RequestBody DocumentCancelTaskDTO dto) {
        return success(tabDocumentService.cancelTask(datasetId, documentId, dto, CREATE_ID));
    }

    /**
     * 更新知识库文档
     */
    @Log(title = "文档", businessType = BusinessType.DELETE)
    @DeleteMapping("{datasetId}/document/{documentId}")
    public AjaxResult remove(@PathVariable String datasetId, @PathVariable String documentId) {
        return success(tabDocumentService.batchDelete(datasetId, new DocumentBatchDeleteDTO(documentId), CREATE_ID));
    }

    /**
     * 分割文档
     */
    @Log(title = "文档", businessType = BusinessType.UPLOAD)
    @PostMapping("document/split")
    public AjaxResult split(@RequestParam("file") List<MultipartFile> fileList,
                            @RequestParam(required = false) String patterns,
                            @RequestParam(required = false) Integer limit,
                            @RequestParam(value = "with_filter", required = false) Boolean withFilter) throws IOException {
        log.info("fileList.size:[{}], patterns:[{}], limit:[{}], withFilter:[{}]", fileList.size(), patterns, limit, withFilter);

        List<DocumentSplitVO> documentSplitVOList = new ArrayList<>();
        for (MultipartFile multipartFile : fileList) {
            String originalFilename = multipartFile.getOriginalFilename();

            List<String> lines = IOUtils.readLines(multipartFile.getInputStream(), StandardCharsets.UTF_8);
            String content = StringUtils.joinWith(StringUtils.EMPTY, lines.toArray());

            DocumentSplitVO documentSplitVO = new DocumentSplitVO(originalFilename);
            documentSplitVO.addDocumentSplit(content);
            documentSplitVOList.add(documentSplitVO);
        }
        return success(documentSplitVOList);
    }

    /**
     * 获取分割参数
     */
    @GetMapping("document/split_pattern")
    public AjaxResult splitPattern() {
        // TODO 配置分割模式
        String patternJsonText = "[{\"key\":\"#\",\"value\":\"(?<=^)# .*|(?<=\\\\n)# .*\"},{\"key\":\"##\",\"value\":\"(?<=\\\\n)(?<!#)## (?!#).*|(?<=^)(?<!#)## (?!#).*\"},{\"key\":\"###\",\"value\":\"(?<=\\\\n)(?<!#)### (?!#).*|(?<=^)(?<!#)### (?!#).*\"},{\"key\":\"####\",\"value\":\"(?<=\\\\n)(?<!#)#### (?!#).*|(?<=^)(?<!#)#### (?!#).*\"},{\"key\":\"#####\",\"value\":\"(?<=\\\\n)(?<!#)##### (?!#).*|(?<=^)(?<!#)##### (?!#).*\"},{\"key\":\"######\",\"value\":\"(?<=\\\\n)(?<!#)###### (?!#).*|(?<=^)(?<!#)###### (?!#).*\"},{\"key\":\"-\",\"value\":\"(?<! )- .*\"},{\"key\":\"空格\",\"value\":\"(?<! ) (?! )\"},{\"key\":\"分号\",\"value\":\"(?<!；)；(?!；)\"},{\"key\":\"逗号\",\"value\":\"(?<!，)，(?!，)\"},{\"key\":\"句号\",\"value\":\"(?<!。)。(?!。)\"},{\"key\":\"回车\",\"value\":\"(?<!\\\\n)\\\\n(?!\\\\n)\"},{\"key\":\"空行\",\"value\":\"(?<!\\\\n)\\\\n\\\\n(?!\\\\n)\"}]";
        return success(JSON.parseArray(patternJsonText));
    }

    /**
     * 获取知识库文档列表
     */
    @GetMapping("{datasetId}/document")
    public AjaxResult list(@PathVariable String datasetId) {
        return success(tabDocumentService.list(datasetId, new DocumentQueryDTO()));
    }

}
